/*
 * FileName:       app_sync_usertask.c
 * Author:         Kingsea  Version: v1.0  Date: 2019-5-16
 * Description:    
 * History:        
 *     <author>   	<version>    	<time>    	<desc>
 *     Kingsea   	v1.0    	2019-5-16    
 */
#include "main.h"
#include "app_sync_usertask.h"
#include "app_asyn_usertask.h"
/****************************************************/
#define uart_return(...) 		uart_printf(__VA_ARGS__)
#define wireless_return(...) 	nus_printf(__VA_ARGS__)
#define sync_return(...) 		sync_printf(__VA_ARGS__)

static uint32_t (*sync_printf)(const void *, ...);
//////////////////////////////////////////////////////////////////////////
static int JL_strToken2Ary(char *str_ptr, const char *filter_ptr, char *tokenAry[], int aryMax)
{
    char *inner_ptr=NULL;
    int   argc = 0;
    char *outer_ptr = strtok_r(str_ptr, filter_ptr, &inner_ptr);
    while (outer_ptr)
    {
        tokenAry[argc++] = outer_ptr;
        outer_ptr = strtok_r(NULL, filter_ptr, &inner_ptr);
        if(argc>=aryMax) break;
    }
    return argc; // real number of strings.
}

static uint32_t host_sys_command_sub(int32_t argc, char *    argv[]);
static uint32_t host_ble_command_sub(int32_t argc, char *    argv[]);
static uint32_t host_gpio_command_sub(int32_t argc, char *    argv[]);
static uint32_t host_user_command_sub(int32_t argc, char *    argv[]);
static void host_command_main(int32_t argc, char *    argv[])
{
    if (argc>0)
    {
        NRF_LOG_DEBUG("%s",argv[0]);

		if (
			(host_ble_command_sub(argc, argv) == NRF_ERROR_NOT_FOUND) &&
			(host_gpio_command_sub(argc, argv) == NRF_ERROR_NOT_FOUND) &&
			(host_sys_command_sub(argc, argv) == NRF_ERROR_NOT_FOUND) &&
			(host_user_command_sub(argc, argv) == NRF_ERROR_NOT_FOUND) 
			)
		{
		}
    }
}

void SY_AppCommand_Exec(char *sz_cmd)
{
    char *    argv[16] = {0};
    int32_t argc = 0;
    
    argc = JL_strToken2Ary(sz_cmd, " ", argv, sizeof(argv)/sizeof(argv[0]));

	if (argc>0)
	{
		if (argv[0][0] == ':')
		{
			argv[0]++;
			sync_printf = nus_printf;
		}
		else 
		{
			sync_printf = uart_printf;
		}
	    host_command_main(argc, argv);
	}
}

//////////////////////////////////////////////////////////////////////////
/**@brief Thread for handling the System do command.
 *
 * @details This thread is responsible for processing send data to Smartphone.
 *
 * @param[in]   arg   Pointer used for passing some arbitrary information (context) from the
 *                    osThreadCreate() call to the thread.
 */
static void host_do_open(void)
{
	// enable system
	NRF_LOG_DEBUG("enable sys.");
	if (getCurrentConnHandle() == BLE_CONN_HANDLE_INVALID)
	{
		uint32_t err_code;
		(void) sd_ble_gap_adv_stop();
	    err_code = ble_advertising_start(getAdvertisingObject(), BLE_ADV_MODE_FAST);
	    APP_ERROR_CHECK(err_code);
	}
}
static void host_do_close(void)
{
	// disable system. stop all function
	NRF_LOG_DEBUG("disable sys.");
	if (getCurrentConnHandle() != BLE_CONN_HANDLE_INVALID)
	{
		uint32_t err_code;
		err_code = sd_ble_gap_disconnect(getCurrentConnHandle(),
                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        if (err_code != NRF_ERROR_INVALID_STATE)
        {
            APP_ERROR_CHECK(err_code);
        }
	}
	sd_ble_gap_adv_stop();
	main_bsp_indication_set(BSP_INDICATE_IDLE);
}
static void host_do_reset()
{
	nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET);
}
static void host_do_dfu(void)
{
	uint32_t err_code;
    err_code = sd_power_gpregret_clr(0, 0xffffffff);
    //APP_ERROR_CHECK(err_code);

    err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
    //APP_ERROR_CHECK(err_code);

    // Signal that DFU mode is to be enter to the power management module
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);

	UNUSED_VARIABLE(err_code);
}

static uint32_t host_sys_command_sub(int32_t argc, char *    argv[])
{
	if (argv[0][0] == '#')
	{
        if (strcmp(argv[0],"#open") == 0)
        {
            host_do_open();
            sync_return("%s ok\r\n", argv[0]);
        }
        else
        if (strcmp(argv[0],"#close") == 0)
        {
            host_do_close();
            sync_return("%s ok\r\n", argv[0]);
        }
        else
        if (strcmp(argv[0],"#getinfo") == 0)
        {
            ble_gap_addr_t ble_addr;
			uint32_t err_code;
            err_code = sd_ble_gap_addr_get(&ble_addr);
            if (err_code == NRF_SUCCESS)
            {
                sync_return("%s ok", argv[0]);
                sync_return(" %02X-%02X-%02X-%02X-%02X-%02X", 
                    ble_addr.addr[0],ble_addr.addr[1],ble_addr.addr[2],
                    ble_addr.addr[3],ble_addr.addr[4],ble_addr.addr[5]);
                sync_return(" %s %s\r\n", SW_MAIN_VERSION_S, __TIME__" "__DATE__);
            }
            //else {sync_return("%s fail\r\n", argv[0]);}
        }
        else
        if (strcmp(argv[0],"#reset") == 0)
        {
            sync_return("%s ok\r\n", argv[0]);
			vTaskDelay(APP_TIMER_TICKS(200));//nrf_delay_ms(200);//
            host_do_reset();
        }
        else
        if (strcmp(argv[0],"#dfu") == 0)
        {
            sync_return("%s ok\r\n", argv[0]);
			vTaskDelay(APP_TIMER_TICKS(200));//nrf_delay_ms(200);//
            host_do_dfu();
        }
		else
        if (strcmp(argv[0],"#gettemp") == 0)
        {
			int32_t temp;
			if (NRF_SUCCESS == sd_temp_get(&temp))
			{
				sync_return("%s ok %d\r\n", argv[0], temp*25);
			}
			//else {sync_return("%s fail\r\n", argv[0]);}
        }
		else
        if (strcmp(argv[0],"#iopen") == 0)
        {
            host_do_open();
        }
        else
        if (strcmp(argv[0],"#iclose") == 0)
        {
            host_do_close();
        }
		else
		{
			return NRF_ERROR_NOT_SUPPORTED;
		}
		return NRF_SUCCESS;
	}
	return NRF_ERROR_NOT_FOUND;
}

//////////////////////////////////////////////////////////////////////////
#if NRF_MODULE_ENABLED(BLE_NUS)
const unsigned char hex2val_tabL[] =
{
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
static uint32_t nus_hexstring_sendout(const uint8_t * p_hexString)
{
    uint32_t ret_val = NRF_ERROR_INVALID_PARAM;
    static uint8_t nus_sendout_ary[NRF_SDH_BLE_GATT_MAX_MTU_SIZE];
    uint16_t length;
    for (length=0; p_hexString[0] && p_hexString[1]; p_hexString+=2)
    {
        nus_sendout_ary[length++] = (hex2val_tabL[p_hexString[0]]<<4)+hex2val_tabL[p_hexString[1]];
        if(length >= sizeof(nus_sendout_ary)/sizeof(nus_sendout_ary[0])) break;
    }
    if (length>0)
    {
        nus_sendout_ary[length] = 0;// NRF_LOG_INFO("%s",nus_sendout_ary);
        ret_val = wireless_return("%s", nus_sendout_ary);
    }
    return ret_val;
}
#endif // BLE_NUS_ENABLED

static uint32_t host_ble_command_sub(int32_t argc, char *    argv[])
{
	#if NRF_MODULE_ENABLED(BLE_NUS)
	if (argv[0][0] == '!')
	{
		uint32_t err_code;
        if (strcmp(argv[0],"!ble_send") == 0) // char * HexString(FIFO), return uint32_t err_code: 0/others
        {
            err_code = (argc>1)?nus_hexstring_sendout((const uint8_t *)argv[1]):NRF_SUCCESS;
            sync_return("%s ok 0x%08X\r\n", argv[0], err_code);
        }
        else
        if (strcmp(argv[0],"!ble_conn") == 0) // return int32_t conn_handle:-1~0, 48bit BT addr: 12 HexString(LSB)
        {
            if (get_nus_object()->conn_handle == BLE_CONN_HANDLE_INVALID)
            {
                sync_return("%s ok 0x%04X\r\n", argv[0], get_nus_object()->conn_handle);
            }
            else
            {
				extern ble_gap_addr_t m_peer_addr_ary[];
                sync_return("%s ok 0x%04X ", argv[0], get_nus_object()->conn_handle);
                sync_return("%02X-%02X-%02X-%02X-%02X-%02X\r\n", 
                    m_peer_addr_ary[get_nus_object()->conn_handle].addr[0],
                    m_peer_addr_ary[get_nus_object()->conn_handle].addr[1],
                    m_peer_addr_ary[get_nus_object()->conn_handle].addr[2],
                    m_peer_addr_ary[get_nus_object()->conn_handle].addr[3],
                    m_peer_addr_ary[get_nus_object()->conn_handle].addr[4],
                    m_peer_addr_ary[get_nus_object()->conn_handle].addr[5] );
            }
        }
		else
		{
			return NRF_ERROR_NOT_SUPPORTED;
		}
		return NRF_SUCCESS;
	}
	#endif // BLE_NUS_ENABLED
	return NRF_ERROR_NOT_FOUND;
}

//////////////////////////////////////////////////////////////////////////
static uint32_t nrf_gpio_port_read(void)
{
	uint32_t masks;
	nrf_gpio_ports_read(0, 1, &masks);
	return masks;
}
static const GPIO_OP_FP_ST cnRF_GPIO_op = {
	nrf_gpio_port_read,
	nrf_gpio_pin_read,
	nrf_gpio_pin_set,
	nrf_gpio_pin_clear,
	nrf_gpio_pin_toggle,
	nrf_gpio_cfg_output,
	(void(*)(uint32_t,int32_t))nrf_gpio_cfg_input
};
const GPIO_OP_FP_ST * gp_GPIO_OP_IFs[] = {
	&cnRF_GPIO_op,
	NULL,
};
bool SY_Register_gpioIF(uint32_t port_number, const GPIO_OP_FP_ST * pfn_IF)
{
	if (port_number < sizeof(gp_GPIO_OP_IFs)/sizeof(gp_GPIO_OP_IFs[0]))
	{
		gp_GPIO_OP_IFs[port_number] = pfn_IF;
		return true;
	}
	return false;
}

const GPIO_OP_FP_ST * sGet_IF(uint32_t pin_number)
{
	uint32_t port_number = pin_number/32;
	return (port_number<(sizeof(gp_GPIO_OP_IFs)/sizeof(gp_GPIO_OP_IFs[0])) && gp_GPIO_OP_IFs[port_number])?gp_GPIO_OP_IFs[port_number]:NULL;
}
static uint32_t host_gpio_command_sub(int32_t argc, char *    argv[])
{
	if (argv[0][0] == '@')
	{
		uint32_t err_code;
		const GPIO_OP_FP_ST * pIF;
        if (strcmp(argv[0],"@gpio_port_read") == 0) // uint32_t port_number:0~1; return uint32_t status:0x00ABCDEF
        {
            if (argc>1)
            {
                uint32_t port_number;
				if (sscanf(argv[1], "%i", &port_number) > 0)
				{
					pIF = sGet_IF(port_number*32);
					if (pIF)
					{
						err_code = pIF->gpio_port_read();
						sync_return("%s ok 0x%X\r\n", argv[0], err_code);
					}
				}
            }
        }
        if (strcmp(argv[0],"@gpio_read") == 0) // uint32_t pin_number:0~63; return uint32_t status:0/1
        {
            if (argc>1)
            {
                uint32_t pin_number;
				if (sscanf(argv[1], "%i", &pin_number) > 0)
				{
					pIF = sGet_IF(pin_number);
					if (pIF)
					{
		                err_code = pIF->gpio_pin_read(pin_number%32);
		                sync_return("%s ok %d\r\n", argv[0], err_code);
					}
				}
            }
        }
        else
        if (strcmp(argv[0],"@gpio_set") == 0) // uint32_t pin_number:0~63
        {
            if (argc>1)
            {
                uint32_t pin_number;
				if (sscanf(argv[1], "%i", &pin_number) > 0)
				{
					pIF = sGet_IF(pin_number);
					if (pIF)
					{
		                pIF->gpio_pin_set(pin_number%32);
		                sync_return("%s ok\r\n", argv[0]);
					}
				}
            }
        }
        else
        if (strcmp(argv[0],"@gpio_clear") == 0) // uint32_t pin_number:0~63
        {
            if (argc>1)
            {
                uint32_t pin_number;
				if (sscanf(argv[1], "%i", &pin_number) > 0)
				{
					pIF = sGet_IF(pin_number);
					if (pIF)
					{
		                pIF->gpio_pin_clear(pin_number%32);
		                sync_return("%s ok\r\n", argv[0]);
					}
				}
            }
        }
        else
        if (strcmp(argv[0],"@gpio_toggle") == 0) // uint32_t pin_number:0~63
        {
            if (argc>1)
            {
                uint32_t pin_number;
				if (sscanf(argv[1], "%i", &pin_number) > 0)
				{
					pIF = sGet_IF(pin_number);
					if (pIF)
					{
		                pIF->gpio_pin_toggle(pin_number%32);
		                sync_return("%s ok\r\n", argv[0]);
					}
				}
            }
        }
        else
        if (strcmp(argv[0],"@gpio_cfg_output") == 0) // uint32_t pin_number:0~63
        {
            if (argc>1)
            {
                uint32_t pin_number;
				if (sscanf(argv[1], "%i", &pin_number) > 0)
				{
					pIF = sGet_IF(pin_number);
					if (pIF)
					{
		                pIF->gpio_cfg_output(pin_number%32);
		                sync_return("%s ok\r\n", argv[0]);
					}
				}
            }
        }
        else
        if (strcmp(argv[0],"@gpio_cfg_input") == 0) // uint32_t pin_number:0~63, nrf_gpio_pin_pull_t pull_config:0/1/3 /*0:float,1:PL,3:PH*/
        {
            if (argc>2)
            {
                uint32_t pin_number;
                uint32_t pull_config;
				if (sscanf(argv[1], "%i", &pin_number) > 0
					&& sscanf(argv[2], "%i", &pull_config) > 0)
				{
					pIF = sGet_IF(pin_number);
					if (pIF)
					{
						pIF->gpio_cfg_input(pin_number%32, (int32_t)pull_config);
						sync_return("%s ok\r\n", argv[0]);
					}
				}
            }
        }
 		else
		{
			return NRF_ERROR_NOT_SUPPORTED;
		}
		return NRF_SUCCESS;
	}
	return NRF_ERROR_NOT_FOUND;
}

//////////////////////////////////////////////////////////////////////////
static uint32_t host_user_command_sub(int32_t argc, char *argv[])
{
	if (argc>1)
	{
		const char *pszRet = "no";
        if (strcmp(argv[0],"Set") == 0) // 
        {
			if (strcmp(argv[1],"Act") == 0)
			{
				int32_t iActID;
				if ((argc>2)
					&& (sscanf(argv[2], "%i", &iActID) > 0)
					&& (iActID !=0)
					&& AS_setDoAction(iActID, argv[3]))
				{
					pszRet = "ok";
				}
			}
			else
			if (strcmp(argv[1],"CAct") == 0)
			{
				AS_setCancelAction();
				pszRet = "ok";
			}
			sync_return("%s %s\r\n", argv[0], pszRet);
        }
		else
        if (strcmp(argv[0],"Get") == 0) //
        {
			if (strcmp(argv[1],"Act") == 0)
			{
				char *pt = pvPortMalloc(256);
				if (pt)
				{
					AS_GetActReturn(pt);
					sync_return("Get Act %u %s\r\n", AS_GetActStatus(), pt);
					vPortFree(pt);
				}
				else
				sync_return("Get Act %u\r\n", AS_GetActStatus());
			}
			else
			if (strcmp(argv[1],"Info") == 0)
			{
	            ble_gap_addr_t ble_addr;
				uint32_t err_code;
	            err_code = sd_ble_gap_addr_get(&ble_addr);
				if (err_code == NRF_SUCCESS)
				{
					sync_return("Get Info %02X-%02X-%02X-%02X-%02X-%02X %s,%u %s\r\n", 
	                    ble_addr.addr[0],ble_addr.addr[1],ble_addr.addr[2],
	                    ble_addr.addr[3],ble_addr.addr[4],ble_addr.addr[5],
	                    SW_MAIN_VERSION_S, AS_GetDeviceType(), __TIME__" "__DATE__
						);
				}
			}
		}
		else
		{
			return NRF_ERROR_NOT_FOUND;//NRF_ERROR_NOT_SUPPORTED;//
		}
		return NRF_SUCCESS;
	}
	return NRF_ERROR_NOT_FOUND;
}


